import Application from "../../src/Application";
import Graphic from "../../src/graphics/Graphic";
import CanvasMouseEvent from "../../src/events/CanvasMouseEvent";
import ELayout from "../../src/enums/ELayout";
import Rectangle from "../../src/geom/Rectangle";
import Vector2 from "../../src/maths/Vector2";
import Size from "../../src/geom/Size";
import Math2D from "../../src/maths/Math2D";

export default class TestApplication extends Application {
    private _context2D: CanvasRenderingContext2D;
    public graphic: Graphic;
    private _mouseX: number = 0;
    private _mouseY: number = 0;

    public constructor(canvas: HTMLCanvasElement) {
        super(canvas);
        this._context2D = canvas.getContext('2d') as CanvasRenderingContext2D;
        this.graphic = new Graphic(canvas);
        this.isSupportMouseMove = true;
    }

    public render() {
        if (this._context2D !== null) {
            this._context2D.clearRect(0, 0, this.canvas.width, this.canvas.height);
            this.drawCanvasCoordCenter();
            this.graphic.strokeGrid();
            // this.doTransform0();
            this.drawCoordInfo(`坐标：[${(this._mouseX).toFixed(2)},${(this._mouseY).toFixed(2)}]角度：${0}`, this._mouseX, this._mouseY);
        }
    }

    /**
     * *覆写基类的受保护方法dispatchMouseMove
     * @param evt 
     */
    protected dispatchMouseMove(evt: CanvasMouseEvent): void {
        // 必须要设置this.isSupportMouseMove = true才能处理mouseMove事件
        this._mouseX = evt.canvasPosition.x;
        this._mouseY = evt.canvasPosition.y;
        // this._tank.onMouseMove(evt);
    }

    /**
     * *计算两点之间的距离
     * @param x0 
     * @param y0 
     * @param x1 
     * @param y1 
     */
    public distance(x0: number, y0: number, x1: number, y1: number): number {
        let diffX: number = x1 - x0;
        let diffY: number = y1 - y0;
        return Math.sqrt(diffX * diffX + diffY * diffY);
    }

    /**
     * *用来绘制Canvas画布的中心点及相交于中心点的x和y轴
     */
    public drawCanvasCoordCenter(): void {
        if (this._context2D === null) {
            return;
        }
        // 计算出Canvas的中心点坐标
        let halfWidth: number = this.canvas.width * 0.5;
        let halfHeight: number = this.canvas.height * 0.5;
        this._context2D.save();
        this._context2D.lineWidth = 2;
        // 使用alpha为0.5的红色来绘制x轴
        this._context2D.strokeStyle = 'rgba(255,0,0,0.5)';
        this.graphic.strokeLine(0, halfHeight, this.canvas.width, halfHeight);
        // 使用alpha为0.5的蓝色来绘制y轴
        this._context2D.strokeStyle = 'rgba(0,0,255,0.5)';
        this.graphic.strokeLine(halfWidth, 0, halfWidth, this.canvas.height);
        this._context2D.restore();
        // 使用alpha为0.5的黑色来绘制画布中心点
        this.graphic.fillCircle(halfWidth, halfHeight, 5, 'rgba(0,0,0,0.5)');
    }

    /**
     * *绘制某个点处的坐标信息
     * @param info 
     * @param x 
     * @param y 
     */
    public drawCoordInfo(info: string, x: number, y: number): void {
        this.graphic.fillText(info, x, y, 'black', 'center', 'bottom');
    }
    public doTransform0(): void {
        if (this._context2D !== null) {
            // 要绘制的矩形的尺寸
            let width: number = 100;
            let height: number = 60;
            // 计算出画布中心点坐标
            let x: number = this.canvas.width * 0.5;
            let y: number = this.canvas.height * 0.5;
            this._context2D.save();
            // 调用translate平移到画布中心
            this._context2D.translate(x, y);
            this.graphic.fillRectWithTitle(0, 0, width, height, '0度旋转');
            this._context2D.restore();
        }
    }

    public doTransform(degree: number, rotateFirst: boolean = true): void {
        // 将角度转换为弧度，由此可见，本方法的参数degree是以角度而不是弧度表示
        let radians: number = Math2D.toRadian(degree);
        // 顺时针旋转
        this._context2D?.save();
        // 根据rotateFirst进行平移和旋转变换
        if (rotateFirst) {
            // 先顺时针旋转20°
            this._context2D?.rotate(radians);
            // 然后再平移到画布中心
            this._context2D?.translate(this.canvas.width * 0.5, this.canvas.height * 0.5);
        } else {
            // 和上面正好相反
            this._context2D?.translate(this.canvas.width * 0.5, this.canvas.height * 0.5);
            this._context2D?.rotate(radians);
        }
        this.graphic.fillRectWithTitle(0, 0, 100, 60, `+${degree}度旋转`);
        this._context2D?.restore();
        // 逆时针旋转
        this._context2D?.save();
        // 根据rotateFirst进行平移和旋转变换
        if (rotateFirst) {
            // 先顺时针旋转20°
            this._context2D?.rotate(-radians);
            // 然后再平移到画布中心
            this._context2D?.translate(this.canvas.width * 0.5, this.canvas.height * 0.5);
        } else {
            // 和上面正好相反
            this._context2D?.translate(this.canvas.width * 0.5, this.canvas.height * 0.5);
            this._context2D?.rotate(-radians);
        }
        this.graphic.fillRectWithTitle(0, 0, 100, 60, `-${degree}度旋转`);
        this._context2D?.restore();

        let radius: number = this.distance(0, 0, this.canvas.width * 0.5, this.canvas.height * 0.5);
        this.graphic.strokeCircle(0, 0, radius, 'black');
    }

    public doLocalTransform(): void {
        // 结论1：使用translate、rotate和scale这些方法时，变换的是局部坐标系
        // 结论2：所有绘制操作都是相对于变换后的局部坐标系所进行的
        // 结论3：translate、rotate和scale这些局部坐标系变换方法都具有累积性（Accumulation），每次变换操作是相对于上一次结果的叠加
        if (this._context2D === null) {
            return;
        }
        let width: number = 100;        // 在局部坐标系中显示的rect的width
        let height: number = 60;        // 在局部坐标系中显示的rect的height
        let coordWidth: number = width * 1.2;       // 局部坐标系x轴的长度
        let coordHeight: number = height * 1.2;     // 局部坐标系y轴的长度
        let radius: number = 5;
        this._context2D.save();
        this.graphic.fillLocalRectWithTitle(width, height, '1、初始状态');
        this.graphic.strokeCoord(0, 0, coordWidth, coordHeight);
        this.graphic.fillCircle(0, 0, radius);

        // 将坐标系向右移动到画布的中心，向下移动10个单位，再绘制局部坐标系
        this._context2D.translate(this.canvas.width * 0.5, 10);
        this.graphic.strokeCoord(0, 0, coordWidth, coordHeight);
        this.graphic.fillCircle(0, 0, radius);
        this.graphic.fillLocalRectWithTitle(width, height, '2、平移');

        this._context2D.translate(0, this.canvas.height * 0.5 - 10);
        this.graphic.strokeCoord(0, 0, coordWidth, coordHeight);
        this.graphic.fillCircle(0, 0, radius);
        this.graphic.fillLocalRectWithTitle(width, height, '3、平移到画布中心');

        // 将坐标系继续旋转-120°
        this._context2D.rotate(Math2D.toRadian(-120));
        // 绘制旋转-120°的矩形
        this.graphic.fillLocalRectWithTitle(width, height, '4、旋转-120度');
        this.graphic.strokeCoord(0, 0, coordWidth, coordHeight);
        this.graphic.fillCircle(0, 0, radius);
        // 将坐标系在-120°旋转的基础上再旋转-130°，合计旋转了-250°
        this._context2D.rotate(Math2D.toRadian(-130));
        this.graphic.fillLocalRectWithTitle(width, height, '5、旋转-130度');
        this.graphic.strokeCoord(0, 0, coordWidth, coordHeight);
        this.graphic.fillCircle(0, 0, radius);

        // 沿着局部坐标系的x轴和y轴正方向各自平移100个单位
        this._context2D.translate(100, 100);
        this.graphic.fillLocalRectWithTitle(width, height, '6、局部平移100个单位');
        this.graphic.strokeCoord(0, 0, coordWidth, coordHeight);

        this._context2D.scale(1.5, 2.0);
        this.graphic.fillLocalRectWithTitle(width, height, '7、缩放局部坐标系', ELayout.LEFT_MIDDLE);
        // this.fillLocalRectWithTitle(width, height, '7、x轴局部放大1.5倍，y轴局部放大2倍');
        // this.fillLocalRectWithTitle(width*1.5, height*2.0, '8、放大物体尺寸');
        this.graphic.strokeCoord(0, 0, coordWidth, coordHeight);
        this.graphic.fillCircle(0, 0, radius);
        this._context2D.restore();
    }
    public rotateTranslate(degree: number, layout: ELayout = ELayout.LEFT_TOP, width: number = 40, height: number = 20): void {
        if (this._context2D === null) {
            return;
        }
        let radians: number = Math2D.toRadian(degree);
        // 顺时针旋转
        this._context2D.save();
        // 先顺时针旋转20°
        this._context2D.rotate(radians);
        // 然后再平移到画布中心
        this._context2D.translate(this.canvas.width * 0.5, this.canvas.height * 0.5);
        // 调用新实现的localRect方法
        this.graphic.fillLocalRectWithTitle(width, height, '', layout);
        this._context2D.restore();
    }
}